/*
 * solenoid.h
 *
 *  Created on: 8-Jul-2009
 *      Author: nrqm
 */

#ifndef SOLENOID_H_
#define SOLENOID_H_

#include "../midi/midi.h"

/**
 * The type of drum that a solenoid is to strike.  Currently only the main drum is used.
 */
typedef enum _dt
{
	MAIN=0,
	BASS=1,
	HI_HAT=2,
} DRUM_TYPE;

/**
 * Represents the solenoid that, when activated with a PWM signal, strikes a drum (directly or with a drum stick).
 */
class Solenoid : public MidiNoteOnListener
{
private:

	/// The type of drum this solenoid is to strike (bass, main, or hi-hat)
	DRUM_TYPE type;
	/// The maximum duty cycle that can be applied to the solenoid to avoid damaging the drum.
	uint8_t max_duty_cycle;
	/// The current PWM duty cycle being applied to the solenoid.
	uint8_t duty_cycle;
	/// The Arduino pin on which the solenoid's PWM signal is output.
	uint8_t pwm_pin;
	/// The modulus (mod 3) of the note value (the parameter to DoNoteOn) to which this solenoid responds.
	/// For example, note % 3 == note_divisor ---> this solenoid is triggered.
	uint8_t note_divisor;
	/// Stores the timer value when a solenoid strike starts (in ms).
	uint16_t strike_start_time;
	/// The maximum number of ms that a strike can last (the actual strike time is controlled by the pot).
	/// Must be less than 0xFF.
	const uint8_t strike_timeout;

	/**
	 * Constructor.
	 * \param type The type of drum that this solenoid is to strike (bass, main, or hi-hat).  This determines
	 * 		the maximum duty cycle that can be applied to the solenoid, the Arduino pins used for I/O, and
	 * 		the range of MIDI notes that the solenoid responds to.
	 */
	Solenoid(DRUM_TYPE type);

protected:
	/**
	 * Respond to a MIDI note on command by activating this solenoid to strike its drum.
	 * \param note The note (0-127) that was sent over MIDI.  This determines which drum is to be struck.
	 * \param velocity The force (0-127) with which to strike the drum.  This is proportional to the PWM
	 * 		duty cycle that is sent to the solenoid.
	 */
	void DoNoteOn(uint8_t note, uint8_t velocity);
public:
	/**
	 * Get the Solenoid instance for a type of drum.
	 */
	static Solenoid* GetInstance(DRUM_TYPE type);

	/**
	 * Check to see if PWM needs to be turned off.  This should be called from the application main loop
	 * as often as possible.
	 */
	void CheckSolenoid();
};

#endif /* SOLENOID_H_ */
